package Shale;

import java.util.List;

import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;

/**
 * 单日询量
 *
 * @author leiwenkang <leiwenkang@kuaishou.com>
 * Created on 2020-10-24
 */
@Slf4j
public class QueryProcessor extends AbstractProcessor {

    @Override
    protected void doProcess(ShaleContext context) {
        double pvRemainByAppendTail = queryDailyProcessByAppendTail(context);
//        double pvRemainByBinary = queryByBinary(context, pvRemainByAppendTail);
        double pvRemainByBinary = 0;
        //取较大值
        double pvRemain =  Math.max(pvRemainByBinary, pvRemainByAppendTail);
        context.setResult(pvRemain);
    }

    /**
     * 按照尾部追加的方式进行询量
     */
    protected double queryDailyProcessByAppendTail(ShaleContext context) {
        //本次请求询量
        List<Supply> supplyList = context.getThisDemand().getSupplyList();
        double sum = 0;
        for (Supply supply : supplyList) {
            sum += supply.getRemain();
        }
        return sum;
    }

    /**
     * 按照hwm方式添加新请求进行询量
     */
    private double queryByBinary(ShaleContext context, double pvRemainByAppendTail) {
        Demand thisDemand = context.getThisDemand();
        context.getDemandList().add(thisDemand);

        //每次对本次询量排期重设询量量级，theta和weight值
        resetThisDemand(thisDemand, thisDemand.getSupply());
        //按最大可分配率分配一次
        boolean result = super.allocate(context, false);
        double pvRemain;
        if (result) {
            pvRemain = thisDemand.getQuantity();
        } else {
            pvRemain = binarySearch(context, pvRemainByAppendTail, thisDemand.getSupply());
        }

        return pvRemain;
    }

    /**
     * 二分的方式询量，并返回询量成功的询量值
     */
    private double binarySearch(ShaleContext context, double minPvRemain, double maxPvRemain) {
        double start = minPvRemain; //末尾询量的值为其最小可询的值
        double end = maxPvRemain;
        double pvRemain = 0;
        for (int i = 0; i < ShaleConstant.BINARY_SEARCH_MAX_TIMES; i++) {
            if (end - start <= ShaleConstant.QUANTITY_GAP) {
                break;
            }
            double mid = (start + end) / 2;
            if (mid == 0) {
                return 0;
            }
            resetThisDemand(context.getThisDemand(), mid);
            if (super.allocate(context, false)) {
                pvRemain = mid;
                start = mid;
            } else {
                end = mid;
            }
        }
        return pvRemain;
    }

    private void resetThisDemand(Demand demand, double quantity) {
        demand.setQuantity(quantity);
        demand.setTheta(1.0 * demand.getQuantity() / demand.getSupply());
//        demand.setWeight(demand.getTheta());
    }


}
